﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;

namespace Nhandang
{
    public class Neuron
    {
        public double _bias;
        private double _error;                      // Tong loi
        private double _input;                      // Tong cac input (ket qua ham tong)
        private double _lambda = 6;                 // lamda trong ham sigmoid
        private double _learnRate = 0.5;            // Toc do hoc
        private double _output = double.MinValue;   // Dung de kiem tra gia tri _output
        public List<Weight> _weights;
        public Neuron() { }
        ////////////////////////////////////////////////////////////////////
        // Khoi tao neuron gom cac thong tin:
        // 		+ Cac neuron o tang truoc
        //		+ Cac trong so lien ket tuong ung (random tu 0 den 1)
        ////////////////////////////////////////////////////////////////////
        public Neuron(Layer inputs, Random rnd)
        {
            _weights = new List<Weight>();
            foreach (Neuron input in inputs)
            {
                Weight w = new Weight();
                w.Input = input;
                w.Value = rnd.NextDouble() * 2 - 1;
                _weights.Add(w);
            }
        }
        ////////////////////////////////////////////////////////////////////
        ////////////////////////////////////////////////////////////////////
        // Khoi tao neuron gom cac thong tin:
        // 		+ Cac neuron o tang truoc
        //		+ Cac trong so lien ket tuong ung
        ////////////////////////////////////////////////////////////////////
        public Neuron(Layer inputs, double[] weights)
        {
            int i = 0;
            _weights = new List<Weight>();
            foreach (Neuron input in inputs)
            {
                Weight w = new Weight();
                w.Input = input;
                w.Value = weights[i];
                _weights.Add(w);
                i++;
            }
            _bias = weights[weights.Length - 1];
        }
        // Ham tong, xem them phan ly thuyet mang neuron
        ////////////////////////////////////////////////////////////////////
        public void Activate()
        {
            _input = 0;
            foreach (Weight w in _weights)
            {
                _input += w.Value * w.Input.Output;
            }
        }
        ////////////////////////////////////////////////////////////////////
        // Luu ma tran trong so cua neuron lop an va neuron lop ra
        // Cac trong so cua 1 neuron duoc luu tren 1 dong, cuoi dong la bias
        ////////////////////////////////////////////////////////////////////
        public double ErrorFeedback(Neuron input)
        {
            Weight w = _weights.Find(delegate(Weight t) { return t.Input == input; });
            return _error * Derivative * w.Value;
        }
        ////////////////////////////////////////////////////////////////////
        // Hieu chinh trong so lien ket, dua tren cac cong thuc trong ly thuyet mang neuron
        ////////////////////////////////////////////////////////////////////
        public void AdjustWeights(double value)
        {
            _error = value;
            for (int i = 0; i < _weights.Count; i++)
            {
                _weights[i].Value += _error * Derivative * _learnRate * _weights[i].Input.Output;
            }
            _bias += _error * Derivative * _learnRate;
        }
        ////////////////////////////////////////////////////////////////////
        // Tinh gia tri dao ham cua ham sigmoid
        ////////////////////////////////////////////////////////////////////
        private double Derivative
        {
            get
            {
                double activation = Output;
                return activation * (1 - activation);
            }
        }
        ////////////////////////////////////////////////////////////////////
        // Tinh dau ra cua neuron
        ////////////////////////////////////////////////////////////////////
        public double Output
        {
            get
            {
                if (_output != double.MinValue)
                {
                    return _output;
                }
                return 1 / (1 + Math.Exp(-_lambda * (_input + _bias)));
            }
            set
            {
                _output = value;
            }
        }
    }
}
